home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / pakstuff.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  24.1 KB  |  1,189 lines

  1.  
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <windows.h>
  7. #include "io.h"
  8. #include "pakstuff.h"
  9. #include "unzip.h"
  10. //#include "cmdlib.h"
  11. #include "str.h"
  12.  
  13. int m_nPAKIndex;
  14. FILE* pakfile[16];
  15. struct PACKDirectory    pakdir;
  16. PACKDirPtr                pakdirptr = &pakdir;
  17. UInt16                    dirsize;
  18. boolean                    pakopen = false;
  19. int                        f_type;
  20. DIRECTORY                *paktextures = NULL;
  21. boolean                    HavePakColormap;
  22. UInt32                    PakColormapOffset;
  23. UInt32                    PakColormapSize;
  24. DIRECTORY                *dirhead = NULL;
  25. boolean g_bPK3 = false;
  26. char g_strBasePath[1024];
  27.  
  28. struct PK3FileInfo
  29. {
  30.   unzFile m_zFile;
  31.   char *m_pName;
  32.   unz_s m_zInfo;
  33.   long m_lSize;
  34.   ~PK3FileInfo()
  35.   {
  36.     delete []m_pName;
  37.   }
  38.   bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; }
  39. };
  40.  
  41. #define __PATHSEPERATOR   '/'
  42.  
  43. #define LOG_PAKFAIL
  44.  
  45. #ifdef LOG_PAKFAIL
  46.  
  47. class LogFile
  48. {
  49. public:
  50.   FILE *m_pFile;
  51.   LogFile(const char* pName)
  52.   {
  53.     m_pFile = fopen(pName, "w");
  54.   }
  55.   ~LogFile()
  56.   {
  57.     if (m_pFile)
  58.     {
  59.       fclose(m_pFile);
  60.     }
  61.   }
  62.   void Log(const char *pFormat, ...)
  63.   {
  64.     va_list arg_ptr;
  65.     va_start(arg_ptr, pFormat);
  66.     fprintf(m_pFile, pFormat, arg_ptr);
  67.     va_end(arg_ptr);
  68.   }
  69. };
  70.  
  71. LogFile g_LogFile("c:\\paklog.txt");
  72. #endif
  73.  
  74. template <class T> class StrPtr : public Str
  75. {
  76. protected:
  77.   T* m_pPtr;
  78.   StrPtr()
  79.   {
  80.     m_pPtr = NULL;
  81.   }
  82.  
  83.   StrPtr(const char *pStr, T *p) : Str(pStr)
  84.   {
  85.     m_pPtr = p;
  86.   }
  87.  
  88.   T* Ptr()
  89.   {
  90.     return m_pPtr;
  91.   }
  92.  
  93.   T& Ref()
  94.   {
  95.     return *m_pPtr;
  96.   }
  97.     
  98.  
  99. };
  100. // PtrList
  101. // a list of ptrs
  102. // 
  103. template <class T> class PtrList
  104. {
  105. protected:
  106.   T *m_pPtr;
  107.   PtrList *m_pNext;
  108.  
  109. public:
  110.  
  111.   PtrList()
  112.   {
  113.     m_pNext = NULL;
  114.     m_pPtr = NULL;
  115.   }
  116.  
  117.   PtrList(T *ip)
  118.   {
  119.     m_pNext = NULL;
  120.     m_pPtr = ip;
  121.   }
  122.  
  123.   ~PtrList()
  124.   {
  125.     delete m_pPtr;
  126.   }
  127.  
  128.   PtrList* Next()
  129.   {
  130.     return m_pNext;
  131.   }
  132.  
  133.   void Add(T *ip)
  134.   {
  135.     PtrList *pl = this;
  136.     while (pl && pl->m_pNext)
  137.     {
  138.       pl = pl->Next();
  139.     }
  140.     pl->m_pNext = new PtrList(ip);
  141.   }
  142.  
  143.   void Remove()
  144.   {
  145.     PtrList *p = m_pNext;
  146.     if (p)
  147.     {
  148.       while (p->m_pNext != this && p->m_pNext != NULL)
  149.       {
  150.         p = p->m_pNext;
  151.       }
  152.       if (p->m_pNext == this)
  153.       {
  154.         p->m_pNext = m_pNext;
  155.       }
  156.     }
  157.   }
  158.  
  159.   virtual PtrList* Find(T *ip)
  160.   {
  161.     PtrList *p = m_pNext;
  162.     while (p)
  163.     {
  164.       if (*p->m_pPtr == *ip)
  165.       {
  166.         return p;
  167.       }
  168.       p = p->m_pNext;
  169.     }
  170.     return NULL;
  171.   }
  172.  
  173.   // remove vp from the list
  174.   void Remove(T *ip)
  175.   {
  176.     PtrList *p = Find(ip);
  177.     if (p)
  178.     {
  179.       p->Remove();
  180.     }
  181.   }
  182.  
  183.   T* Ptr()
  184.   {
  185.     return m_pPtr;
  186.   }
  187.  
  188.   T& Ref()
  189.   {
  190.     return *m_pPtr;
  191.   }
  192.  
  193.   void RemoveAll()
  194.   {
  195.     PtrList *p = m_pNext;
  196.     while (p)
  197.     {
  198.       PtrList *p2 = p;
  199.       p = p->m_pNext;
  200.       delete p2;
  201.     }
  202.   }
  203. };
  204.  
  205.  
  206. typedef PtrList<unzFile> ZFileList;
  207. typedef PtrList<Str> StrList;
  208. typedef PtrList<PK3FileInfo> PK3List;
  209.  
  210.  
  211. StrList g_PK3TexturePaths;
  212. PK3List g_PK3Files;
  213. ZFileList g_zFiles;
  214. #define WORK_LEN 1024
  215. #define TEXTURE_PATH "textures"
  216. #define PATH_SEPERATORS "/\\:\0"
  217.  
  218.  
  219. char* __StrDup(char* pStr)
  220.   if (pStr)
  221.   {
  222.     return strcpy(new char[strlen(pStr)+1], pStr); 
  223.   }
  224.   return NULL;
  225. }
  226.  
  227. char* __StrDup(const char* pStr)
  228.   if (pStr)
  229.   {
  230.     return strcpy(new char[strlen(pStr)+1], pStr); 
  231.   }
  232.   return NULL;
  233. }
  234.  
  235. #define MEM_BLOCKSIZE 4096
  236. void* __qblockmalloc(size_t nSize)
  237. {
  238.     void *b;
  239.   // round up to threshold
  240.   int nAllocSize = nSize % MEM_BLOCKSIZE;
  241.   if ( nAllocSize > 0)
  242.   {
  243.     nSize += MEM_BLOCKSIZE - nAllocSize;
  244.   }
  245.     b = malloc(nSize + 1);
  246.     memset (b, 0, nSize);
  247.     return b;
  248. }
  249.  
  250. void* __qmalloc (size_t nSize)
  251. {
  252.     void *b;
  253.     b = malloc(nSize + 1);
  254.     memset (b, 0, nSize);
  255.     return b;
  256. }
  257.  
  258.  
  259. /*
  260. ====================
  261. Extract file parts
  262. ====================
  263. */
  264. void __ExtractFilePath (const char *path, char *dest)
  265. {
  266.     const char *src;
  267.  
  268.     src = path + strlen(path) - 1;
  269.  
  270. //
  271. // back up until a \ or the start
  272. //
  273.     while (src != path && *(src-1) != __PATHSEPERATOR)
  274.         src--;
  275.  
  276.     memcpy (dest, path, src-path);
  277.     dest[src-path] = 0;
  278. }
  279.  
  280. void __ExtractFileName (const char *path, char *dest)
  281. {
  282.     const char *src;
  283.  
  284.     src = path + strlen(path) - 1;
  285.  
  286. //
  287. // back up until a \ or the start
  288. //
  289.     while (src != path && *(src-1) != '/' 
  290.          && *(src-1) != '\\' )
  291.         src--;
  292.  
  293.     while (*src)
  294.     {
  295.         *dest++ = *src++;
  296.     }
  297.     *dest = 0;
  298. }
  299.  
  300. void __ExtractFileBase (const char *path, char *dest)
  301. {
  302.     const char *src;
  303.  
  304.     src = path + strlen(path) - 1;
  305.  
  306. //
  307. // back up until a \ or the start
  308. //
  309.     while (src != path && *(src-1) != '/' 
  310.          && *(src-1) != '\\' )
  311.         src--;
  312.  
  313.     while (*src && *src != '.')
  314.     {
  315.         *dest++ = *src++;
  316.     }
  317.     *dest = 0;
  318. }
  319.  
  320. void __ExtractFileExtension (const char *path, char *dest)
  321. {
  322.     const char *src;
  323.  
  324.     src = path + strlen(path) - 1;
  325.  
  326. //
  327. // back up until a . or the start
  328. //
  329.     while (src != path && *(src-1) != '.')
  330.         src--;
  331.     if (src == path)
  332.     {
  333.         *dest = 0;    // no extension
  334.         return;
  335.     }
  336.  
  337.     strcpy (dest,src);
  338. }
  339.  
  340.  
  341. void __ConvertDOSToUnixName( char *dst, const char *src )
  342. {
  343.     while ( *src )
  344.     {
  345.         if ( *src == '\\' )
  346.             *dst = '/';
  347.         else
  348.             *dst = *src;
  349.         dst++; src++;
  350.     }
  351.     *dst = 0;
  352. }
  353.  
  354.  
  355.  
  356.  
  357.  
  358. void AddSlash(Str& str)
  359. {
  360.   int nLen = str.GetLength();
  361.   if (nLen > 0)
  362.   {
  363.     if (str[nLen-1] != '\\' && str[nLen-1] != '/')
  364.       str += '\\';
  365.   }
  366. }
  367.  
  368. void FindReplace(Str& strContents, const char* pTag, const char* pValue)
  369. {
  370.   if (strcmp(pTag, pValue) == 0)
  371.     return;
  372.   for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag))
  373.   {
  374.     int nRightLen = strContents.GetLength() - strlen(pTag) - nPos;
  375.     Str strLeft(strContents.Left(nPos));
  376.     Str strRight(strContents.Right(nRightLen));
  377.     strLeft += pValue;
  378.     strLeft += strRight;
  379.     strContents = strLeft;
  380.   }
  381. }
  382.  
  383.  
  384.  
  385.  
  386.  
  387. void ProgError(char *errstr, ...)
  388. {
  389.   va_list args;
  390.  
  391.   va_start(args, errstr);
  392.   printf("\nProgram Error: *** ");
  393.   vprintf(errstr, args);
  394.   printf(" ***\n");
  395.   va_end(args);
  396.   exit(5);
  397. }
  398.  
  399. boolean ReadBytes(FILE *file, void *addr, UInt32 size)
  400. {
  401.   while (size > 0x8000)
  402.     {
  403.       if (fread(addr, 1, 0x8000, file) != 0x8000)
  404.     return false;
  405.       addr = (char *)addr + 0x8000;
  406.       size -= 0x8000;
  407.     }
  408.   if (fread(addr, 1, size, file) != size)
  409.     return false;
  410.   return true;
  411. }
  412. int ReadMagic(FILE *file)
  413. {
  414.   UInt8 buf[4];
  415.  
  416.   if (ReadBytes(file, buf, 4) == FALSE)
  417.     return FTYPE_ERROR;
  418.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IWAD", 4))
  419.     return FTYPE_IWAD;
  420.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "PWAD", 4))
  421.     return FTYPE_PWAD;
  422.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "PACK", 4))
  423.     return FTYPE_PACK;
  424.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "WAD2", 4))
  425.     return FTYPE_WAD2;
  426.   if (buf[0] == 0x17 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
  427.     return FTYPE_BSP;
  428.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IDPO", 4))
  429.     return FTYPE_MODEL;
  430.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "IDSP", 4))
  431.     return FTYPE_SPRITE;
  432.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "RIFF", 4))
  433.     return FTYPE_WAV;
  434.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), ".snd", 4))
  435.     return FTYPE_AU;
  436.   if (buf[0] == 'P')
  437.     {
  438.       if (buf[1] == '1')
  439.     return FTYPE_PBM_ASC;
  440.       if (buf[1] == '2')
  441.     return FTYPE_PGM_ASC;
  442.       if (buf[1] == '3')
  443.     return FTYPE_PPM_ASC;
  444.       if (buf[1] == '4')
  445.     return FTYPE_PBM_RAW;
  446.       if (buf[1] == '5')
  447.     return FTYPE_PGM_RAW;
  448.       if (buf[1] == '6')
  449.     return FTYPE_PPM_RAW;
  450.     }
  451.   if (buf[0] == 'B' && buf[1] == 'M')
  452.     return FTYPE_BMP;
  453.   if (!strncmp(reinterpret_cast<const char*>(&buf[0]), "GIF8", 4))
  454.     return FTYPE_GIF;
  455.   if (buf[0] == 0x0a && buf[1] == 0x05 && buf[2] == 0x01 && buf[3] == 0x08)
  456.     return FTYPE_PCX;
  457.   return FTYPE_UNKNOWN;
  458. }
  459. FILE *OpenFileReadMagic(const char *filename, int *ftype_r)
  460. {
  461.   FILE *f;
  462.  
  463.   *ftype_r = FTYPE_ERROR;
  464.   if ((f = fopen(filename, "rb")) == NULL)
  465.     return NULL;
  466.   *ftype_r = ReadMagic(f);
  467.   if (*ftype_r == FTYPE_ERROR)
  468.     {
  469.       fclose(f);
  470.       return NULL;
  471.     }
  472.   return f;
  473. }
  474. boolean WriteBytes(FILE *file, void *addr, UInt32 size)
  475. {
  476.   while (size > 0x8000)
  477.     {
  478.       if (fwrite(addr, 1, 0x8000, file) != 0x8000)
  479.     return FALSE;
  480.       addr = (char *)addr + 0x8000;
  481.       size -= 0x8000;
  482.     }
  483.   if (fwrite(addr, 1, size, file) != size)
  484.     return FALSE;
  485.   return TRUE;
  486. }
  487. char *ConvertFilePath(char *filename)
  488. {
  489.   char *cp;
  490.   
  491.   if (filename == NULL)
  492.     ProgError("BUG: cannot convert a NULL pathname");
  493.   for (cp = filename; *cp; cp++)
  494.     if (*cp == '/' || *cp == '\\')
  495.       {
  496. #ifdef QEU_DOS
  497.     *cp = '\\';
  498. #else
  499.     *cp = '/';
  500. #endif
  501.       }
  502.   return filename;
  503. }
  504.  
  505. /*
  506.  * Read the PACK directory into memory.  The optional offset to the
  507.  * start of the PACK file is given in "offset".  The number of files in
  508.  * the directory is returned in *dirsize_r.
  509.  */
  510. PACKDirPtr ReadPACKDirectory(FILE *packfile, UInt32 offset, UInt16 *dirsize_r)
  511. {
  512.   PACKDirPtr dir;
  513.   UInt32     pos, size;
  514.   UInt16     max, i;
  515.  
  516.   *dirsize_r = 0;
  517.   if (packfile == NULL)
  518.     return NULL;
  519.   if ((fseek(packfile, offset, SEEK_SET) < 0)
  520.       || (ReadMagic(packfile) != FTYPE_PACK)
  521.       || (ReadInt32(packfile, &pos) == FALSE)
  522.       || (ReadInt32(packfile, &size) == FALSE)
  523.       || (size == 0L)
  524.       || (size / sizeof(struct PACKDirectory) > 65535L)
  525.       || (fseek(packfile, offset + pos, SEEK_SET) < 0))
  526.     return NULL;
  527.   dir = (PACKDirPtr)__qmalloc(size);
  528.   max = (UInt16)(size / sizeof(struct PACKDirectory));
  529.   for (i = 0; i < max; i++)
  530.     {
  531.       if (ReadBytes(packfile, &dir[i], sizeof(struct PACKDirectory)) == FALSE)
  532.     {
  533.       free(dir);
  534.       return NULL;
  535.     }
  536.       ConvertFilePath(dir[i].name);
  537.       dir[i].offset = SwapInt32(dir[i].offset);
  538.       dir[i].size = SwapInt32(dir[i].size);
  539.     }
  540.   *dirsize_r = max;
  541.   return dir;
  542. }
  543.  
  544. /*
  545.  * Print the contents of the PACK directory in "outf".
  546.  */
  547. void DumpPACKDirectory(FILE *outf, PACKDirPtr dir, UInt16 dirsize)
  548. {
  549.     UInt16 i;
  550.     UInt32 sum;
  551.     char   buf[57];
  552.  
  553.     if (outf == NULL || dir == NULL || dirsize == 0)
  554.         return;
  555.     fprintf(outf, "num    offset     size    file name\n");
  556.     fprintf(outf, "       (hex)      (dec)\n");
  557.     sum = 0L;
  558.     for (i = 0; i < dirsize; i++)
  559.     {
  560.         if(!strnicmp(dir[i].name, "textures", 8))
  561.         {
  562.           strncpy(buf, dir[i].name, 56);
  563.           buf[56] = '\0';
  564.           fprintf(outf, "%3u  0x%08lx  %6ld   %s\n",
  565.               i, dir[i].offset, dir[i].size, buf);
  566.           sum += dir[i].size;
  567.         }
  568.     }
  569.     fprintf(outf, "\nTotal size for %3u entries:  %7lu bytes.\n", dirsize, sum);
  570.     fprintf(outf, "Size of the PACK directory:  %7lu bytes.\n",
  571.         (UInt32)dirsize * (UInt32)sizeof(struct PACKDirectory));
  572.     fprintf(outf, "Total (header + data + dir): %7lu bytes.\n",
  573.         12L + sum + (UInt32)dirsize * (UInt32)sizeof(struct PACKDirectory));
  574. }
  575.  
  576. void ClearFileList(FILELIST **list)
  577. {
  578.     FILELIST    *temp;
  579.  
  580.     while(*list)
  581.     {
  582.         temp = *list;
  583.         *list = (*list)->next;
  584.         free(temp);
  585.     }
  586. }
  587.  
  588. void ClearDirList(DIRLIST **list)
  589. {
  590.     DIRLIST    *temp;
  591.  
  592.     while(*list)
  593.     {
  594.         temp = *list;
  595.         *list = (*list)->next;
  596.         free(temp);
  597.     }
  598. }
  599.  
  600. DIRECTORY *FindPakDir(DIRECTORY *dir, char *name)
  601. {
  602.     DIRECTORY    *currentPtr;
  603.  
  604.     for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next)
  605.     {
  606.         if(!stricmp(name, currentPtr->name))
  607.         {
  608.             return currentPtr;
  609.         }
  610.     }
  611.     return NULL;
  612. }
  613.  
  614.  
  615. // LoadPK3FileList
  616. // ---------------
  617. //
  618. // This gets passed a file mask which we want to remove as 
  619. // we are only interested in the directory name and any given
  620. // extension. Only handles explicit filenames or *.something
  621. //
  622. boolean LoadPK3FileList(FILELIST **filelist, const char *pattern)
  623. {
  624.   char cSearch[WORK_LEN];
  625.     __ConvertDOSToUnixName( cSearch, pattern );
  626.   char cPath[WORK_LEN];
  627.   char cExt[WORK_LEN];
  628.   char cFile[WORK_LEN];
  629.   char cWork[WORK_LEN];
  630.   __ExtractFilePath(pattern, cPath);
  631.   __ExtractFileName(pattern, cFile);
  632.   __ExtractFileExtension(pattern, cExt);
  633.   const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile;
  634.   strcpy(cWork, cPath);
  635.   sprintf(cPath, "textures/%s", cWork);
  636.  
  637.   PK3List *p = g_PK3Files.Next();
  638.   while (p != NULL)
  639.   {
  640.     // qualify the path
  641.     PK3FileInfo *pKey = p->Ptr();
  642.     if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare))
  643.     {
  644.       __ExtractFileName(pKey->m_pName, cWork); 
  645.       AddToFileListAlphabetized(filelist, cWork, 0, 0, false);
  646.     }
  647.     p = p->Next();
  648.   }
  649.   return (*filelist) != NULL;
  650. }
  651.  
  652. boolean GetPackFileList(FILELIST **filelist, char *pattern)
  653. {
  654.     char                    *str1, *str2;
  655.     int                        i;
  656.     DIRECTORY                *dummy = paktextures;
  657.     FILELIST                *temp;
  658.  
  659.     if (!pakopen)
  660.         return false;
  661.  
  662.   if (g_bPK3)
  663.   {
  664.     return LoadPK3FileList(filelist, pattern);
  665.   }
  666.  
  667.     str1 = pattern;
  668.  
  669.     for(i = 0; pattern[i] != '\0'; i++)
  670.     {
  671.         if(pattern[i] == '\\')
  672.             pattern[i] = '/';
  673.     }
  674.  
  675.     while(strchr(str1, '/'))
  676.     {
  677.         str2 = strchr(str1, '/');
  678.         *str2++ = '\0';
  679.         dummy = FindPakDir(dummy, str1);
  680.         if(!dummy)
  681.             return false;
  682.         str1 = str2;
  683.     }
  684.     for(temp = dummy->files; temp; temp=temp->next)
  685.     {
  686.       AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false);
  687.     }
  688.     return true;
  689. }
  690.  
  691. boolean GetPackTextureDirs(DIRLIST **dirlist)
  692. {
  693.     UInt16                    i;
  694.     char                    buf[57];
  695.  
  696.     if (!pakopen)
  697.         return 1;
  698.  
  699.   if (g_bPK3)
  700.   {
  701.     StrList *pl = g_PK3TexturePaths.Next();
  702.     while (pl != NULL)
  703.     {
  704.       AddToDirListAlphabetized(dirlist, pl->Ref(), 0);
  705.       pl = pl->Next();
  706.     }
  707.     return true;
  708.   }
  709.  
  710.     for (i = 0; i < dirsize; i++)
  711.     {
  712.         if(!strnicmp(pakdirptr[i].name, "textures", 8))
  713.         {
  714.             strncpy(buf, &(pakdirptr[i].name[9]), 46);
  715.             if(strchr(buf, '\\'))
  716.               *strchr(buf, '\\') = '\0';
  717.             else if(strchr(buf, '/'))
  718.               *strchr(buf, '/') = '\0';
  719.             else
  720.               buf[56] = '\0';
  721.  
  722.             if(strchr(buf, '.'))
  723.                 continue;
  724.  
  725.             AddToDirListAlphabetized(dirlist, buf, 0);
  726.         }
  727.     }
  728.     return true;
  729. }
  730.  
  731. boolean AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from)
  732. {
  733.     DIRLIST    *currentPtr, *previousPtr, *newPtr;
  734.  
  735.     strlwr(dirname);
  736.     for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)
  737.     {
  738.         if(!stricmp(dirname, currentPtr->dirname))
  739.         {
  740.             return false;
  741.         }
  742.     }
  743.     previousPtr = NULL;
  744.     currentPtr = *list;
  745.  
  746.     if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL)
  747.         return false;
  748.  
  749.     strcpy(newPtr->dirname, dirname);
  750.     newPtr->from = from;
  751.  
  752.     while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0)
  753.     {
  754.         previousPtr = currentPtr;
  755.         currentPtr = currentPtr->next;
  756.     } //End while
  757.     if(previousPtr == NULL)
  758.     {
  759.         newPtr->next = *list;
  760.         *list = newPtr;
  761.     } //End if
  762.     else
  763.     {
  764.         previousPtr->next = newPtr;
  765.         newPtr->next = currentPtr;
  766.     } //End else
  767.     return true;
  768. }
  769.  
  770. boolean AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, boolean dirs)
  771. {
  772.     FILELIST    *currentPtr, *previousPtr, *newPtr;
  773.  
  774.     for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next)
  775.     {
  776.         if(!stricmp(filename, currentPtr->filename))
  777.         {
  778.             return false;
  779.         }
  780.     }
  781.     previousPtr = NULL;
  782.     currentPtr = *list;
  783.  
  784.     if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL)
  785.         return false;
  786.  
  787.     strcpy(newPtr->filename, filename);
  788.     newPtr->offset = offset;
  789.     newPtr->size = size;
  790.  
  791.     while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0)
  792.     {
  793.         previousPtr = currentPtr;
  794.         currentPtr = currentPtr->next;
  795.     } //End while
  796.     if(previousPtr == NULL)
  797.     {
  798.         newPtr->next = *list;
  799.         *list = newPtr;
  800.     } //End if
  801.     else
  802.     {
  803.         previousPtr->next = newPtr;
  804.         newPtr->next = currentPtr;
  805.     } //End else
  806.     return true;
  807. }
  808.  
  809. boolean PakLoadFile(const char *filename, void **bufferptr)
  810. {
  811.     FILELIST    *p = NULL;
  812.     DIRECTORY    *dummy;
  813.     void        *buffer;
  814.     char        *str1, *str2;
  815.  
  816.     if(!pakopen)
  817.         return false;
  818.  
  819.   Str str(filename);
  820.   __ConvertDOSToUnixName(str, str);
  821.  
  822.     dummy = paktextures;
  823.     str1 = str;
  824.  
  825.     while(strchr(str1, '/'))
  826.     {
  827.         str2 = strchr(str1, '/');
  828.         *str2++ = '\0';
  829.         dummy = FindPakDir(dummy, str1);
  830.         if(!dummy)
  831.             return false;
  832.         str1 = str2;
  833.     }
  834.  
  835.   // FIXME: add error handling routines
  836.     for(p = dummy->files; p; p = p->next)
  837.     {
  838.         if(!stricmp(str1, p->filename))
  839.         {
  840.             if (fseek(pakfile[m_nPAKIndex], p->offset, SEEK_SET) < 0)
  841.             {
  842.                 //Sys_Printf("Unexpected EOF in pakfile\n");
  843.                 return false;
  844.             }
  845.             if((buffer = __qmalloc(p->size+5)) == NULL)
  846.                 //Error("Could not allocate memory");
  847.     
  848.             if(fread(buffer, 1, p->size, pakfile[m_nPAKIndex]) != p->size)
  849.             {
  850.                 //Sys_Printf("Error reading %s from pak\n", str1);
  851.                 free(buffer);
  852.                 return false;
  853.             }
  854.             *bufferptr = buffer;
  855.             return true;
  856.         }
  857.     }
  858.     return false;
  859. }
  860.  
  861. int PakLoadAnyFile(const char *filename, void **bufferptr)
  862. {
  863.   char cWork[WORK_LEN];
  864.   if (g_bPK3)
  865.   {
  866.     PK3FileInfo *pInfo;
  867.     Str strKey;
  868.     // need to lookup the file without the base/texture path on it
  869.     Str strBase(g_strBasePath);
  870.     AddSlash(strBase);
  871.     __ConvertDOSToUnixName(cWork, strBase);
  872.     Str strFile(filename);
  873.     __ConvertDOSToUnixName(strFile, strFile);
  874.     strFile.MakeLower();
  875.     strlwr(cWork);
  876.     FindReplace(strFile, cWork, "");
  877.  
  878.     PK3FileInfo infoFind;
  879.     infoFind.m_pName = __StrDup(strFile.GetBuffer());
  880.     PK3List *pList = g_PK3Files.Find(&infoFind);
  881.     if (pList)
  882.     {
  883.       pInfo = pList->Ptr();
  884.       memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s));
  885.       if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK)
  886.       {
  887.         void *buffer = __qblockmalloc(pInfo->m_lSize+1);
  888.         int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize);
  889.         *bufferptr = buffer;
  890.         unzCloseCurrentFile(pInfo->m_zFile);
  891.         return n;
  892.       }
  893.     }
  894. #ifdef LOG_PAKFAIL
  895.     sprintf(cWork, "PAK failed on %s\n", filename);
  896.     g_LogFile.Log(cWork);
  897. #endif
  898.     return -1;
  899.   }
  900.  
  901.     for (int i = 0; i < dirsize; i++)
  902.     {
  903.         if(!stricmp(filename, pakdirptr[i].name))
  904.         {
  905.             if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0)
  906.       {
  907.           void *buffer = __qmalloc (pakdirptr[i].size+1);
  908.           ((char *)buffer)[pakdirptr[i].size] = 0;
  909.               if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size)
  910.         {
  911.           *bufferptr = buffer;
  912.           return pakdirptr[i].size;
  913.         }
  914.       }
  915.         }
  916.     }
  917. #ifdef LOG_PAKFAIL
  918.     sprintf(cWork, "PAK failed on %s\n", filename);
  919.     g_LogFile.Log(cWork);
  920. #endif
  921.   return -1;
  922. }
  923.  
  924.  
  925.  
  926. DIRECTORY *AddPakDir(DIRECTORY **dir, char *name)
  927. {
  928.     DIRECTORY    *currentPtr, *previousPtr, *newPtr;
  929.  
  930.     for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next)
  931.     {
  932.         if(!stricmp(name, currentPtr->name))
  933.         {
  934.             return currentPtr;
  935.         }
  936.     }
  937.     previousPtr = NULL;
  938.     currentPtr = *dir;
  939.  
  940.     if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL)
  941.         return NULL;
  942.  
  943.     strcpy(newPtr->name, name);
  944.     newPtr->files = NULL;
  945.  
  946.     while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0)
  947.     {
  948.         previousPtr = currentPtr;
  949.         currentPtr = currentPtr->next;
  950.     }
  951.     if(previousPtr == NULL)
  952.     {
  953.         newPtr->next = *dir;
  954.         *dir = newPtr;
  955.     }
  956.     else
  957.     {
  958.         previousPtr->next = newPtr;
  959.         newPtr->next = currentPtr;
  960.     }
  961.     return newPtr;
  962. }
  963.  
  964.  
  965. // OpenPK3
  966. // -------
  967. // Opens a PK3 ( or zip ) file and creates a list of filenames
  968. // and zip info structures
  969. // 
  970. boolean OpenPK3(const char *filename)
  971. {
  972.   char cFilename[WORK_LEN];
  973.   char cName[WORK_LEN];
  974.   char cWork[WORK_LEN];
  975.   unz_file_info zInfo;
  976.   unzFile *zFile = new unzFile(unzOpen(filename));
  977.   g_zFiles.Add(zFile);
  978.   if (zFile != NULL)
  979.   {
  980.     int nStatus = unzGoToFirstFile(*zFile);
  981.     while (nStatus == UNZ_OK)
  982.     {
  983.       cFilename[0] = '\0';
  984.       unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0);
  985.       strlwr(cFilename);
  986.         __ConvertDOSToUnixName( cWork, cFilename);
  987.       if (strstr(cWork, ".") != NULL)
  988.       {
  989.         PK3FileInfo *pInfo = new PK3FileInfo();
  990.         pInfo->m_pName = __StrDup(cWork);
  991.         memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s));
  992.         pInfo->m_lSize = zInfo.uncompressed_size;
  993.         pInfo->m_zFile = *zFile;
  994.         g_PK3Files.Add(pInfo);
  995.       }
  996.       char *p = strstr(cFilename, TEXTURE_PATH);
  997.       if (p != NULL)
  998.       {
  999.         // FIXME: path differences per os ?
  1000.         // catch solo directory entry
  1001.         if (strlen(p) > strlen(TEXTURE_PATH) + 1)
  1002.         {
  1003.           // skip textures + path seperator
  1004.           p += strlen(TEXTURE_PATH) + 1;
  1005.           int nEnd = strcspn(p, PATH_SEPERATORS);
  1006.           strncpy(cName, p, nEnd);
  1007.           cName[nEnd] = '\0';
  1008.  
  1009.           boolean bFound = false;
  1010.           StrList *pl = g_PK3TexturePaths.Next();
  1011.           while (pl != NULL)
  1012.           {
  1013.             if (strcmpi(pl->Ref(), cName) == 0)
  1014.             {
  1015.               // already have this, continue
  1016.               bFound = true;
  1017.               break;
  1018.             }
  1019.             pl = pl->Next();
  1020.           }
  1021.           if (!bFound)
  1022.           {
  1023.             g_PK3TexturePaths.Add(new Str(cName));
  1024.           }
  1025.         }
  1026.       }
  1027.       nStatus = unzGoToNextFile(*zFile);
  1028.     }
  1029.   }
  1030.   return (zFile != NULL);
  1031. }
  1032.  
  1033. void closePK3(unzFile zf)
  1034. {
  1035.   unzClose(zf);
  1036. }
  1037.  
  1038. void OpenPakFile(const char *filename)
  1039. {
  1040.     int            i;
  1041.     char        *str1, *str2;
  1042.     DIRECTORY    *dummy;
  1043.  
  1044.     if(!pakopen)
  1045.         paktextures = NULL;
  1046.  
  1047.     HavePakColormap = false;
  1048.  
  1049.   Str strTest(filename);
  1050.   strTest.MakeLower();
  1051.   if (strTest.Find("pk3") >= 0 || strTest.Find("zip") >= 0)
  1052.   {
  1053.     pakopen = g_bPK3 = OpenPK3(filename);
  1054.     return;
  1055.   }
  1056.  
  1057.  
  1058.     if((pakfile[m_nPAKIndex] = OpenFileReadMagic(filename, &f_type)) == NULL)
  1059.     {
  1060.     //FIXME: error routine
  1061.         //Sys_Printf("ERROR: Could not open %s", filename);
  1062.         return;
  1063.     }
  1064.     if(f_type != FTYPE_PACK)
  1065.     {
  1066.         //Sys_Printf("ERROR: %s is not a valid pack file", filename);
  1067.         if(f_type != FTYPE_ERROR)
  1068.             fclose(pakfile[m_nPAKIndex]);
  1069.         return;
  1070.     }
  1071.     pakdirptr = ReadPACKDirectory(pakfile[m_nPAKIndex], 0, &dirsize);
  1072.     if (pakdirptr == NULL)
  1073.     {
  1074.         //Sys_Printf("ERROR: Could not read pack directory", filename);
  1075.         fclose(pakfile[m_nPAKIndex]);
  1076.         return;
  1077.     }
  1078.     if (dirsize == 0)
  1079.     {
  1080.         fclose(pakfile[m_nPAKIndex]);
  1081.         return;
  1082.     }
  1083.     for (i = 0; i < dirsize; i++)
  1084.     {
  1085.         if(!strnicmp("textures/", pakdirptr[i].name, 9))
  1086.         {
  1087.             dummy = paktextures;
  1088.             str1 = pakdirptr[i].name+9;
  1089.             while(strchr(str1, '/'))
  1090.             {
  1091.                 str2 = strchr(str1, '/');
  1092.                 *str2++ = '\0';
  1093.                     dummy = AddPakDir(dummy==paktextures?&paktextures:&dummy, str1);
  1094.                 str1 = str2;
  1095.             }
  1096.  
  1097.             AddToFileListAlphabetized(&(dummy->files), str1, pakdirptr[i].offset, pakdirptr[i].size, true);
  1098.         }
  1099.         else if(!strnicmp("pics/colormap.pcx", pakdirptr[i].name, 17))
  1100.         {
  1101.             HavePakColormap = true;
  1102.             PakColormapOffset = pakdirptr[i].offset;
  1103.             PakColormapSize = pakdirptr[i].size;
  1104.         }
  1105.     }
  1106.     pakopen = true;
  1107.  
  1108. }
  1109.  
  1110. void ClearPaKDir(DIRECTORY **dir)
  1111. {
  1112.     DIRECTORY    *d1 = *dir, *d2;
  1113.  
  1114.     while(d1)
  1115.     {
  1116.         ClearFileList(&(d1->files));
  1117.         d2 = d1;
  1118.         d1 = d1->next;
  1119.         free(d2);
  1120.     }
  1121. }
  1122.  
  1123. void CleanUpPakDirs()
  1124. {
  1125.   ClearPaKDir(&paktextures);
  1126.   paktextures = NULL;
  1127.   dirhead = NULL;
  1128.   g_PK3TexturePaths.RemoveAll();
  1129.   g_PK3Files.RemoveAll();
  1130. }
  1131.  
  1132. void ClosePakFile(void)
  1133. {
  1134.     if(pakopen)
  1135.   {
  1136.     if (g_bPK3)
  1137.     {
  1138.       ZFileList *p = g_zFiles.Next();
  1139.       while (p != NULL)
  1140.       {
  1141.         unzFile uz = p->Ref();
  1142.         closePK3(uz);
  1143.         p = p->Next();
  1144.       }
  1145.     }
  1146.     else
  1147.     {
  1148.       fclose(pakfile[m_nPAKIndex]);
  1149.     }
  1150.   }
  1151.     pakopen = false;
  1152.   CleanUpPakDirs();
  1153. }
  1154.  
  1155.  
  1156. void WINAPI InitPakFile(const char * pBasePath, const char *pName)
  1157. {
  1158.   m_nPAKIndex = 0;
  1159.   pakopen = false;
  1160.     paktextures = NULL;
  1161.   strcpy(g_strBasePath, pBasePath);
  1162.   if (pName == NULL)
  1163.   {
  1164.     char cWork[WORK_LEN];
  1165.       Str strPath(pBasePath);
  1166.     AddSlash(strPath);
  1167.       strPath += "*.pk3";
  1168.       bool bGo = true;
  1169.       struct _finddata_t fileinfo;
  1170.       int handle = _findfirst (strPath, &fileinfo);
  1171.       if (handle != -1)
  1172.       {
  1173.           do
  1174.           {
  1175.         sprintf(cWork, "%s\\%s", pBasePath, fileinfo.name);
  1176.         OpenPakFile(cWork);
  1177.           } while (_findnext( handle, &fileinfo ) != -1);
  1178.         _findclose (handle);
  1179.     }
  1180.     }
  1181.   else
  1182.   {
  1183.       OpenPakFile(pName);
  1184.   }
  1185. }
  1186.  
  1187.